﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

namespace Miao
{
    /// <summary>
    /// 容量限制的对象池包装类
    /// 当活跃对象数量超过最大容量时，自动回收最早获取的对象
    /// </summary>
    /// <typeparam name="T">对象池中对象的类型</typeparam>
    public class CapacityLimitedObjectPool<T> : IDisposable where T : class
    {
        #region 私有字段
        private readonly IObjectPool<T> _innerPool;
        private readonly Queue<T> _activeObjects;
        private readonly int _maxCapacity;
        private readonly Action<T> _onObjectRecycled;
        private bool _disposed = false;
        #endregion

        #region 公共属性
        /// <summary>
        /// 当前活跃对象数量
        /// </summary>
        public int ActiveCount => _activeObjects.Count;

        /// <summary>
        /// 最大容量
        /// </summary>
        public int MaxCapacity => _maxCapacity;

        /// <summary>
        /// 内部对象池的统计信息（如果支持）
        /// </summary>
        public int CountAll => _innerPool is ObjectPool<T> pool ? pool.CountAll : -1;
        public int CountActive => _innerPool is ObjectPool<T> pool ? pool.CountActive : -1;
        public int CountInactive => _innerPool is ObjectPool<T> pool ? pool.CountInactive : -1;
        #endregion

        #region 构造函数
        /// <summary>
        /// 创建容量限制的对象池
        /// </summary>
        /// <param name="innerPool">内部对象池</param>
        /// <param name="maxCapacity">最大活跃对象容量</param>
        /// <param name="onObjectRecycled">对象被自动回收时的回调（可选）</param>
        public CapacityLimitedObjectPool(IObjectPool<T> innerPool, int maxCapacity, Action<T> onObjectRecycled = null)
        {
            if (innerPool == null)
                throw new ArgumentNullException(nameof(innerPool));
            if (maxCapacity <= 0)
                throw new ArgumentException("Max capacity must be greater than 0", nameof(maxCapacity));

            _innerPool = innerPool;
            _maxCapacity = maxCapacity;
            _activeObjects = new Queue<T>(maxCapacity);
            _onObjectRecycled = onObjectRecycled;
        }

        /// <summary>
        /// 创建容量限制的对象池（使用Unity的ObjectPool）
        /// </summary>
        /// <param name="createFunc">创建对象的函数</param>
        /// <param name="actionOnGet">获取对象时的回调</param>
        /// <param name="actionOnRelease">释放对象时的回调</param>
        /// <param name="actionOnDestroy">销毁对象时的回调</param>
        /// <param name="maxCapacity">最大活跃对象容量</param>
        /// <param name="collectionCheck">是否进行集合检查</param>
        /// <param name="defaultCapacity">对象池默认容量</param>
        /// <param name="maxSize">对象池最大容量</param>
        /// <param name="onObjectRecycled">对象被自动回收时的回调（可选）</param>
        public CapacityLimitedObjectPool(
            Func<T> createFunc,
            Action<T> actionOnGet = null,
            Action<T> actionOnRelease = null,
            Action<T> actionOnDestroy = null,
            int maxCapacity = 10,
            bool collectionCheck = true,
            int defaultCapacity = 10,
            int maxSize = 10000,
            Action<T> onObjectRecycled = null)
        {
            if (createFunc == null)
                throw new ArgumentNullException(nameof(createFunc));
            if (maxCapacity <= 0)
                throw new ArgumentException("Max capacity must be greater than 0", nameof(maxCapacity));

            _innerPool = new ObjectPool<T>(
                createFunc,
                actionOnGet,
                actionOnRelease,
                actionOnDestroy,
                collectionCheck,
                defaultCapacity,
                maxSize);

            _maxCapacity = maxCapacity;
            _activeObjects = new Queue<T>(maxCapacity);
            _onObjectRecycled = onObjectRecycled;
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 从对象池获取对象
        /// 如果活跃对象数量达到最大容量，会自动回收最早的对象
        /// </summary>
        /// <returns>从对象池获取的对象</returns>
        public T Get()
        {
            ThrowIfDisposed();

            // 如果达到最大容量，回收最早的对象
            if (_activeObjects.Count >= _maxCapacity)
            {
                T oldestObject = _activeObjects.Dequeue();
                _onObjectRecycled?.Invoke(oldestObject);
                _innerPool.Release(oldestObject);
            }

            // 获取新对象
            T newObject = _innerPool.Get();
            _activeObjects.Enqueue(newObject);
            return newObject;
        }

        /// <summary>
        /// 手动释放对象到对象池
        /// </summary>
        /// <param name="obj">要释放的对象</param>
        /// <returns>如果对象在活跃列表中并成功释放则返回true，否则返回false</returns>
        public bool Release(T obj)
        {
            ThrowIfDisposed();

            if (obj == null)
                return false;

            // 从活跃对象队列中移除（需要转换为列表来操作）
            var activeList = new List<T>(_activeObjects);
            bool removed = activeList.Remove(obj);

            if (removed)
            {
                // 重建队列
                _activeObjects.Clear();
                foreach (var item in activeList)
                {
                    _activeObjects.Enqueue(item);
                }

                _innerPool.Release(obj);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 清空所有活跃对象
        /// </summary>
        public void Clear()
        {
            ThrowIfDisposed();

            while (_activeObjects.Count > 0)
            {
                T obj = _activeObjects.Dequeue();
                _onObjectRecycled?.Invoke(obj);
                _innerPool.Release(obj);
            }
        }

        /// <summary>
        /// 获得当前被激活的Objects
        /// </summary>
        /// <returns></returns>
        public IReadOnlyCollection<T> GetActiveObjects()
        {
            return _activeObjects;
        }

        /// <summary>
        /// 尝试获取最早的活跃对象（不移除）
        /// </summary>
        /// <param name="oldestObject">最早的活跃对象</param>
        /// <returns>如果有活跃对象则返回true</returns>
        public bool TryPeekOldest(out T oldestObject)
        {
            ThrowIfDisposed();
            return _activeObjects.TryPeek(out oldestObject);
        }
        #endregion

        #region IDisposable实现
        public void Dispose()
        {
            if (_disposed)
                return;

            Clear();

            if (_innerPool is IDisposable disposablePool)
            {
                disposablePool.Dispose();
            }

            _disposed = true;
        }

        private void ThrowIfDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(CapacityLimitedObjectPool<T>));
        }
        #endregion
    }

    #region 扩展方法
    /// <summary>
    /// 对象池扩展方法
    /// </summary>
    public static class ObjectPoolExtensions
    {
        /// <summary>
        /// 为现有对象池添加容量限制
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="pool">现有对象池</param>
        /// <param name="maxCapacity">最大容量</param>
        /// <param name="onObjectRecycled">对象被回收时的回调</param>
        /// <returns>容量限制的对象池包装</returns>
        public static CapacityLimitedObjectPool<T> WithCapacityLimit<T>(
            this IObjectPool<T> pool,
            int maxCapacity,
            Action<T> onObjectRecycled = null) where T : class
        {
            return new CapacityLimitedObjectPool<T>(pool, maxCapacity, onObjectRecycled);
        }
    }
    #endregion
}